package main

import (
	"database/sql"
	"fmt"
	"log"
	"os"
)

// main函数是程序的入口点，根据命令行参数执行不同的数据库示例
func main() {
	// 可选的命令行参数来选择数据库类型
	args := os.Args[1:]
	if len(args) > 0 {
		switch args[0] {
		case "mysql":
			runMySQLExample()
		case "bigquery":
			runBigQueryExample()
		case "both":
			runBothExample()
		default:
			fmt.Printf("未知的数据库类型: %s\n", args[0])
			fmt.Println("用法: go run main.go [mysql|bigquery|both]")
		}
	} else {
		// 默认运行两种数据库示例
		runBothExample()
	}
}

// runBothExample 同时运行MySQL和BigQuery示例
func runBothExample() {
	fmt.Println("=== 运行MySQL和BigQuery示例 ===")
	runMySQLExample()
	fmt.Println("\n")
	runBigQueryExample()
}

// runMySQLExample 演示如何使用MySQL代理连接和执行各种数据库操作
func runMySQLExample() {
	// 连接到代理服务器，指定MySQL类型和默认连接
	db, err := sql.Open("mysqlproxy", "default@localhost:8080")
	if err != nil {
		log.Fatalf("连接代理服务器失败: %v", err)
	}
	defer db.Close()

	// 测试连接
	if err := db.Ping(); err != nil {
		log.Fatalf("Ping失败: %v", err)
	}
	fmt.Println("成功连接到MySQL代理服务器")

	// 基本查询示例
	basicQueryExample(db, "MySQL")

	// 准备语句示例
	preparedStatementExample(db)

	// 事务示例
	transactionExample(db)
}

// runBigQueryExample 演示如何使用BigQuery代理连接和执行各种数据库操作
func runBigQueryExample() {
	// 连接到代理服务器，指定BigQuery类型和默认连接
	db, err := sql.Open("bigqueryproxy", "default@localhost:8080")
	if err != nil {
		log.Fatalf("连接代理服务器失败: %v", err)
	}
	defer db.Close()

	// 测试连接
	if err := db.Ping(); err != nil {
		log.Fatalf("Ping失败: %v", err)
	}
	fmt.Println("成功连接到BigQuery代理服务器")

	// BigQuery基本查询示例
	basicQueryExample(db, "BigQuery")

	// BigQuery查询公共数据集示例
	fmt.Println("\n=== BigQuery公共数据集查询示例 ===")
	queryPublicDataset(db)

	// BigQuery创建和查询临时表示例
	fmt.Println("\n=== BigQuery临时表示例 ===")
	tempTableExample(db)

	// 尝试事务（应该会返回错误）
	fmt.Println("\n=== BigQuery事务示例（预期会失败）===")
	testBigQueryTransaction(db)
}

// basicQueryExample 演示如何执行基本的SQL查询
func basicQueryExample(db *sql.DB, dbType string) {
	fmt.Printf("\n=== %s基本查询示例 ===\n", dbType)

	// 执行查询
	rows, err := db.Query("SELECT 1 as id, 'Hello' as message")
	if err != nil {
		log.Fatalf("查询失败: %v", err)
	}
	defer rows.Close()

	// 遍历结果
	for rows.Next() {
		var id int
		var message string
		if err := rows.Scan(&id, &message); err != nil {
			log.Fatalf("扫描行数据失败: %v", err)
		}
		fmt.Printf("查询结果: ID=%d, Message=%s\n", id, message)
	}

	if err := rows.Err(); err != nil {
		log.Fatalf("读取行时出错: %v", err)
	}
}

// queryPublicDataset 演示如何查询BigQuery公共数据集
func queryPublicDataset(db *sql.DB) {
	// 查询Google提供的公共数据集
	query := `
		SELECT name, gender, count 
		FROM bigquery-public-data.usa_names.usa_1910_2013
		WHERE state = 'NY' 
		ORDER BY count DESC
		LIMIT 5
	`

	rows, err := db.Query(query)
	if err != nil {
		log.Printf("查询公共数据集失败: %v", err)
		return
	}
	defer rows.Close()

	fmt.Println("纽约州最常见的名字:")
	for rows.Next() {
		var name, gender string
		var count int
		if err := rows.Scan(&name, &gender, &count); err != nil {
			log.Printf("扫描行数据失败: %v", err)
			continue
		}
		genderStr := "女"
		if gender == "M" {
			genderStr = "男"
		}
		fmt.Printf("名字: %s, 性别: %s, 数量: %d\n", name, genderStr, count)
	}
}

// tempTableExample 演示如何在BigQuery中创建和使用临时表
func tempTableExample(db *sql.DB) {
	// 创建临时表
	_, err := db.Exec(`
		CREATE TEMP TABLE temp_data AS
		SELECT 1 as id, 'Alice' as name, 25 as age
		UNION ALL
		SELECT 2 as id, 'Bob' as name, 30 as age
		UNION ALL
		SELECT 3 as id, 'Charlie' as name, 35 as age
	`)

	if err != nil {
		log.Printf("创建临时表失败: %v", err)
		return
	}

	// 查询临时表
	rows, err := db.Query("SELECT * FROM temp_data ORDER BY age")
	if err != nil {
		log.Printf("查询临时表失败: %v", err)
		return
	}
	defer rows.Close()

	fmt.Println("临时表数据:")
	for rows.Next() {
		var id, age int
		var name string
		if err := rows.Scan(&id, &name, &age); err != nil {
			log.Printf("扫描行数据失败: %v", err)
			continue
		}
		fmt.Printf("ID: %d, 姓名: %s, 年龄: %d\n", id, name, age)
	}
}

// testBigQueryTransaction 测试BigQuery事务支持（预期会失败）
func testBigQueryTransaction(db *sql.DB) {
	tx, err := db.Begin()
	if err != nil {
		fmt.Printf("预期的错误: %v\n", err)
		fmt.Println("BigQuery不支持事务，如预期一样失败")
		return
	}

	// 如果意外成功，确保关闭事务
	defer tx.Rollback()
	fmt.Println("意外: BigQuery事务竟然成功了！")
}

// preparedStatementExample 演示如何使用预处理语句
func preparedStatementExample(db *sql.DB) {
	fmt.Println("\n=== 准备语句示例 ===")

	// 创建表（如果不存在）
	_, err := db.Exec(`
		CREATE TABLE IF NOT EXISTS users (
			id INT AUTO_INCREMENT PRIMARY KEY,
			name VARCHAR(50) NOT NULL,
			email VARCHAR(100) UNIQUE
		)
	`)
	if err != nil {
		log.Fatalf("创建表失败: %v", err)
	}

	// 清空表
	_, err = db.Exec("TRUNCATE TABLE users")
	if err != nil {
		log.Fatalf("清空表失败: %v", err)
	}

	// 准备插入语句
	stmt, err := db.Prepare("INSERT INTO users(name, email) VALUES(?, ?)")
	if err != nil {
		log.Fatalf("准备语句失败: %v", err)
	}
	defer stmt.Close()

	// 插入多条记录
	users := []struct {
		name  string
		email string
	}{
		{"张三", "zhangsan@example.com"},
		{"李四", "lisi@example.com"},
		{"王五", "wangwu@example.com"},
	}

	for _, user := range users {
		result, err := stmt.Exec(user.name, user.email)
		if err != nil {
			log.Fatalf("插入数据失败: %v", err)
		}
		id, _ := result.LastInsertId()
		fmt.Printf("插入用户: %s, ID: %d\n", user.name, id)
	}

	// 查询刚插入的数据
	rows, err := db.Query("SELECT id, name, email FROM users ORDER BY id")
	if err != nil {
		log.Fatalf("查询失败: %v", err)
	}
	defer rows.Close()

	fmt.Println("已插入的用户:")
	for rows.Next() {
		var id int
		var name, email string
		if err := rows.Scan(&id, &name, &email); err != nil {
			log.Fatalf("扫描行数据失败: %v", err)
		}
		fmt.Printf("ID: %d, 姓名: %s, 邮箱: %s\n", id, name, email)
	}
}

// transactionExample 演示如何使用数据库事务
func transactionExample(db *sql.DB) {
	fmt.Println("\n=== 事务示例 ===")

	// 开始事务
	tx, err := db.Begin()
	if err != nil {
		log.Fatalf("开始事务失败: %v", err)
	}

	// 在事务中执行多个更新操作
	try := func() error {
		// 更新张三的邮箱
		_, err := tx.Exec("UPDATE users SET email = ? WHERE name = ?",
			"zhangsan_new@example.com", "张三")
		if err != nil {
			return err
		}

		// 插入新用户
		_, err = tx.Exec("INSERT INTO users(name, email) VALUES(?, ?)",
			"赵六", "zhaoliu@example.com")
		if err != nil {
			return err
		}

		// 模拟条件性回滚
		shouldRollback := false
		if shouldRollback {
			return fmt.Errorf("模拟错误，将触发回滚")
		}

		return nil
	}

	// 尝试执行事务，出错时回滚
	if err := try(); err != nil {
		tx.Rollback()
		log.Printf("事务回滚: %v", err)
	} else {
		tx.Commit()
		fmt.Println("事务提交成功")
	}

	// 验证事务结果
	rows, err := db.Query("SELECT id, name, email FROM users ORDER BY id")
	if err != nil {
		log.Fatalf("查询失败: %v", err)
	}
	defer rows.Close()

	fmt.Println("事务后的用户列表:")
	for rows.Next() {
		var id int
		var name, email string
		if err := rows.Scan(&id, &name, &email); err != nil {
			log.Fatalf("扫描行数据失败: %v", err)
		}
		fmt.Printf("ID: %d, 姓名: %s, 邮箱: %s\n", id, name, email)
	}
}
